home *** CD-ROM | disk | FTP | other *** search
- /************************************************************************
- * *
- * Copyright (c) 1982, Fred Fish *
- * All Rights Reserved *
- * *
- * This software and/or documentation is released for public *
- * distribution for personal, non-commercial use only. *
- * Limited rights to use, modify, and redistribute are hereby *
- * granted for non-commercial purposes, provided that all *
- * copyright notices remain intact and all changes are clearly *
- * documented. The author makes no warranty of any kind with *
- * respect to this product and explicitly disclaims any implied *
- * warranties of merchantability or fitness for any particular *
- * purpose. *
- * *
- ************************************************************************
- */
-
-
- /*
- * tgetflag extract boolean termcap capability
- *
- * Returns TRUE if specified id is present in terminal
- * entry, FALSE otherwise.
- *
- */
-
- #include <stdio.h>
- #include <string.h>
- #include <termcap.h>
- #include <ctype.h>
-
- #define TRUE 1
- #define FALSE 0
- #define BUFSIZE 1024 /* Assumed size of external buffer */
-
- #define NO_FILE -1 /* Returned if can't open file */
- #define NO_ENTRY 0 /* Returned if can't find entry */
- #define SUCCESS 1 /* Returned if entry found ok */
- #define TRUNCATED 2 /* Returned if entry found but trunc */
-
- # define DEFAULT_ROOT "termcap" /* name without path component */
- # ifdef __MINT__
- # define DEFAULT_FILE "u:\\etc\\termcap"
- # else
- # define DEFAULT_FILE "/etc/termcap" /* default termcap filename */
- # endif
-
- char *_tcpbuf; /* Termcap entry buffer pointer */
-
- int tgetflag(char *id)
- {
- char *bp;
-
- bp = _tcpbuf;
-
- while ((bp = strchr(bp, ':')) != NULL) {
- bp++;
- if (*bp++ == id[0] && *bp != '\0' && *bp++ == id[1]) {
- if (*bp == '\0' || *bp++ == ':') {
- return(TRUE);
- } else {
- return(FALSE);
- }
- }
- }
- return(FALSE);
- }
-
- /*
- * do_esc process an escaped sequence
- *
- * Processes an escape sequence pointed to by
- * in, transfering it to location pointed to
- * by out, and updating the pointer to in.
- *
- */
-
- static char *maplist = {"E\033b\bf\fn\nr\rt\t"};
-
- static char *do_esc(char *out,char *in)
- { int count;
- char ch;
- char *cp;
-
- if (*in != '\0') {
- if (isdigit(*in)) {
- ch = 0;
- for (count = 0; count < 3 && isdigit(*in); in++) {
- ch <<= 3;
- ch |= (*in - '0');
- }
- *out++ = ch;
- } else if ((cp = strchr(maplist,*in)) != NULL) {
- *out++ = *++cp;
- in++;
- } else {
- *out++ = *in++;
- }
- }
- return(in);
- }
-
- /*
- *
- * decode transfer string capability, decoding escapes
- *
- * DESCRIPTION
- *
- * Transfers the string capability, up to the next ':'
- * character, or null, to the buffer pointed to by
- * the pointer in *area. Note that the initial
- * value of *area and *area is updated to point
- * to the next available location after the null
- * terminating the transfered string.
- *
- * BUGS
- *
- * There is no overflow checking done on the destination
- * buffer, so it better be large enough to hold
- * all expected strings.
- *
- */
-
- static char *decode(char *bp,char **area)
- { char *cp, *bgn;
-
- cp = *area;
- while (*bp != '\0' && *bp != ':') {
- switch(*bp) {
- case '\\':
- bp = do_esc(cp++,++bp);
- break;
- case '^':
- *cp++ = *++bp & 037;
- bp++;
- break;
- default:
- *cp++ = *bp++;
- break;
- }
- }
- *cp++ = '\0';
- bgn = *area;
- *area = cp;
- return(bgn);
- }
-
- /*
- *
- * tgetstr extract string capability from termcap entry
- *
- * Gets the string capability for <id>, placing it in
- * the buffer at *area, and advancing *area to point
- * to next available storage.
- *
- * For example, if the following capabilities are
- * in the termcap file:
- *
- * ZZ=zzzz
- * YY=yyyyyy
- * WW=www
- *
- * then successive calls using YY, ZZ, and WW will
- * build the following buffer:
- *
- * yyyyyy0zzzz0www0
- *
- * The first call will return a pointer to yyyyyy, the
- * second will return a pointer to zzzz and the third
- * will return a pointer to www. Note that each
- * string is null terminated, as are all C strings.
- *
- * Characters preceded by the carot character (\136)
- * are mapped into the corresponding control character.
- * For example, the two character sequence ^A becomes
- * a single control-A (\001) character.
- *
- * The escape character is the normal C backslash and
- * the normal C escape sequences are recognized, along
- * with a special sequence for the ASCII escape character
- * (\033). The recognized sequences are:
- *
- * \E => '\033' (ASCII escape character)
- * \b => '\010' (ASCII backspace character)
- * \f => '\014' (ASCII form feed character)
- * \n => '\012' (ASCII newline/linefeed char)
- * \r => '\015' (ASCII carriage return char)
- * \t => '\011' (ASCII tab character)
- * \ddd => '\ddd' (arbitrary ASCII digit)
- * \x => 'x' (ordinary ASCII character)
- *
- */
-
- char *tgetstr(char *id,char **area)
- {
- char *bp;
-
- bp = _tcpbuf;
- while ((bp = strchr(bp,':')) != NULL) {
- bp++;
- if (*bp++ == id[0] && *bp != '\0' && *bp++ == id[1]) {
- if (*bp != '\0' && *bp++ != '=') {
- return(NULL);
- } else {
- return(decode(bp,area));
- }
- }
- }
- return(NULL);
- }
-
- /*
- *
- * tputs output string with appropriate padding
- *
- * Outputs string pointed to by cp, using function outc, and
- * following it with the appropriate number of padding characters.
- * Affcnt contains the number of lines affected, which is used
- * as a multiplier for the specified per line pad time. If
- * per line pad count is not applicable, affcnt should be 1,
- * NOT zero.
- *
- * The format of the string pointed to by cp is:
- *
- * [pad time][*]<string to send>
- *
- * where: pad time => time to delay in milliseconds
- * * => specifies that time is per line
- *
- * The pad character is assumed to reside in the external
- * variable "PC". Also, the external variable "ospeed"
- * should contain the output speed of the terminal as
- * encoded in /usr/include/sgtty.h (B0-B9600).
- *
- * BUGS
- *
- * Digit conversion is based on native character set
- * being ASCII.
- *
- */
-
- # ifdef SGTTY
- extern char PC; /* Pad character to use */
- extern char ospeed; /* Encoding of output speed */
-
- static int _times[] = {
- 0, /* Tenths of ms per char 0 baud */
- 2000, /* Tenths of ms per char 50 baud */
- 1333, /* Tenths of ms per char 75 baud */
- 909, /* Tenths of ms per char 110 baud */
- 743, /* Tenths of ms per char 134 baud */
- 666, /* Tenths of ms per char 150 baud */
- 500, /* Tenths of ms per char 200 baud */
- 333, /* Tenths of ms per char 300 baud */
- 166, /* Tenths of ms per char 600 baud */
- 83, /* Tenths of ms per char 1200 baud */
- 55, /* Tenths of ms per char 1800 baud */
- 41, /* Tenths of ms per char 2400 baud */
- 20, /* Tenths of ms per char 4800 baud */
- 10 /* Tenths of ms per char 9600 baud */
- };
- # endif
-
- # ifdef SGTTY
- static void do_padding (int ptime, int (*outc )(int));
- # endif
-
- void tputs(char *cp,int affcnt,int (*outc) (int))
- {
- int ptime; /* Pad time in tenths of milliseconds */
-
- if (cp == NULL || *cp == '\0') {
- return;
- } else {
- for (ptime = 0; isdigit(*cp); cp++) {
- ptime *= 10;
- ptime += (*cp - '0');
- }
- ptime *= 10;
- if (*cp == '.') {
- cp++;
- if (isdigit(*cp)) {
- ptime += (*cp++ - '0');
- }
- while (isdigit(*cp)) {cp++;}
- }
- if (*cp == '*') {
- ptime *= affcnt;
- cp++;
- }
- while (*cp != '\0') {
- (*outc)(*cp++);
- }
- # ifdef SGTTY
- do_padding(ptime,outc);
- # endif
- }
- }
-
- # ifdef SGTTY
- /*
- * do_padding transmit any pad characters required
- *
- * Does any padding required as specified by ptime (in tenths
- * of milliseconds), the output speed given in the external
- * variable ospeed, and the pad character given in the
- * external variable PC.
- *
- */
-
-
- static void do_padding(ptime,outc)
- int ptime;
- int (*outc) (int);
- {
- register int nchars;
- register int tpc;
-
- if (ptime != 0) {
- if (ospeed >= 0 && ospeed <= (sizeof(_times)/ sizeof(int))) {
- tpc = _times[ospeed];
- ptime += (tpc / 2);
- nchars = ptime / tpc;
- for ( ; nchars > 0; --nchars) {
- (*outc)(PC);
- }
- }
- }
- }
- # endif
-
- /*
- * build_entry construct termcap entry in a given buffer
- *
- * For a given name build in a buffer bp a termcap description
- * using a contents of file fp. Continue this until the entry
- * is complete or we reached stop. Concatenate entries if
- * required by tc capability. White space characters and
- * backslashes escaping newlines are not copied into bp.
- * Returns SUCCESS if there was no problems, NO_ENTRY if an
- * entry with given name was not found and TRUNCATED if we
- * run out of a buffer space or continuation entry specified
- * with tc was not found
- *
- * BUGS
- *
- * Termcap specifications require for tc to be the last capability
- * for the given name. This is not enforced but anything which
- * follows tc in the same description will be discarded.
- * It is not entirely clear what we should return when continuation
- * specified with tc failed.
- * Other stuff which goes beyond termcap specs can be accepted.
- * Terminal names starting with '#' are not accepted.
- * Continuation with names over 127 characters long will likely bomb!
- *
- * AUTHOR
- *
- * Michal Jaegermann
- *
- */
-
- static int build_entry(char *bp,char *stop,FILE *fp, char *name)
- {
- int c;
- int so_far, skip_all = 0;
- char *np;
- char nbuf[128];
- extern int _tgetc (FILE *fp);
-
- /* rewind file - we may seek for a continuation entry */
- rewind(fp);
-
- /*
- * this is FSM - sort of
- */
- while (EOF != (c = getc(fp))) {
- /*
- * we are looking at a comment - skip it
- */
- if ('#' == c) {
- do {
- if (EOF == (c = getc(fp)))
- return NO_ENTRY;
- } while ('\n' != c);
- }
- /*
- * empty line or we finished comment traversal;
- * a little bit to good - but valid termcap file will be
- * stil accepted
- */
- if (isspace(c))
- continue;
- /*
- * try matching name
- */
- np = name;
- while (*np == c) {
- np += 1;
- c = _tgetc(fp);
- }
- /*
- * we finished traversing our name - is this really a match ?
- */
- if (*np == '\0') {
- if (c == '|' || c == ':')
- break; /* we have a match */
- if (c == EOF)
- return (TRUNCATED); /* match - but we wanted more */
- }
- /*
- * no match - skip until next name or next entry
- * if we are past all possible names here
- */
- skip_all = 0;
- while ('\n' != c) {
- if (':' == c)
- skip_all = 1; /* we are past all valid names for this entry */
- if ('|' == c && 0 == skip_all)
- break;
- c = _tgetc(fp);
- }
- }
- if (EOF == c)
- return (NO_ENTRY);
- while (':' != c) /* skip the remainig variants of terminal names */
- c = _tgetc(fp); /* we do not want any mixups later */
-
- /*
- * at last we got it - copy terminal description into bp
- */
- so_far = 0; /* rough indicator how far we are into a capability */
- while ('\n' != (c = _tgetc(fp))) {
- if (0 == so_far && !isalpha(c))
- continue; /* do not bother with all kind of spurious stuff */
- so_far++;
- if (1 == so_far && 't' == c ) {
- /* a special case - maybe we have "tc=" string? */
- if ((bp + 3) > stop) {
- ungetc(c, fp);
- continue;
- /* cheating with so_far, but we want to skip this case! */
- }
- *bp++ = c;
- c = _tgetc(fp);
- if ('c' == c) {
- *bp++ = c;
- c = _tgetc(fp);
- if ('=' == c) {
- /* we will continue with a name which follows */
- bp -= 2;
- /* copy new name to nbuf */
- np = nbuf;
- while (':' != (c = _tgetc(fp))) {
- if ('\n' == c || EOF == c)
- break;
- *np++ = c;
- }
- *np = '\0';
- return (SUCCESS == build_entry(bp, stop, fp, nbuf) ?
- SUCCESS : TRUNCATED);
- }
- }
- } /* end of 'tc=' check */
- if (':' == c) /* literal colon cannot occur in capabilities strings -
- * one has to use '\072' instead */
- so_far = 0;
- *bp++ = c;
- if (bp >= stop)
- return(TRUNCATED);
- }
- if (bp < stop)
- *bp = '\0';
- return(SUCCESS);
- }
-
- /*
- * Auxilary function to read a character from a text file
- * with skipping escaped line terminators; any escaped
- * '\n' will be replaced by a character which follows.
- * After escape any number of ^M's will vanish,
- * i.e a string of three characters '\\', 0x0d, 'a' will read
- * as a string of two characters '\\', 'a' and so on...
- * We do not tolerate such garbage in text files. :-)
- */
-
- int _tgetc(FILE *fp)
- { int c;
-
- if ('\\' == (c = getc(fp))) {
- while ('\r' == (c = getc(fp)))
- ; /* Messy stuff - go away */
- if (c != '\n') {
- ungetc(c, fp);
- return ('\\');
- }
- c = getc(fp);
- }
- return(c);
- }
-
- #ifdef MINT
- # define PATHSEP ','
- #else
- # define PATHSEP ';'
- #endif
-
- /* Follow the PATH, trying to fopen the file. Takes one additional
- * argument which can be NULL. Otherwise this argument gets filled
- * in the full path to the file. Returns as does fopen().
-
- Fopenp was already defined in stdio.h on the GCC compiler, so I
- renamed it to nfopenp() (Kees Lemmens, 93)
- */
-
- static FILE *
- nfopenp(char *name,char *mode,char *pathname)
- {
- char buffer[BUFSIZ], *buf, *bufp, *pathp, lastch;
- FILE *fp;
- extern char *getenv (const char *);
-
- /* If pathname is given, use it instead of buf so the calling
- * process knows the path we found name under
- */
- if (pathname)
- buf = pathname;
- else
- buf = buffer;
-
- strcpy(buf, name);
- pathp = getenv("PATH");
- while (pathp && *pathp) {
- bufp = buf;
- while (*pathp && *pathp != PATHSEP)
- lastch = *bufp++ = *pathp++;
- if (lastch != '\\')
- *bufp++ = '\\';
- strcpy(bufp, name);
- if ((fp = fopen(buf, mode)) != NULL)
- return fp;
- if (*pathp)
- pathp++;
- }
- return NULL;
- }
-
- /*
- * we do not really need the following part once the stuff is in
- * our termcap buffer
- */
-
- static char term_default[] = "st52:co#80:li#25\
- :al=\\EL:am:bs:cd=\\EJ:ce=\\EK:cl=\\EE:cm=\\EY%+ %+ :dl=\\EM\
- :do=\\EB:eo:ho=\\EH:is=\\Eq\\EE\\Ee\\Ev:it#8:pt:kb=^H:ll=\\EY9!\
- :me=\\Eq:mr=\\Ep:le=\\ED:nd=\\EC:rc=\\Ek:sc=\\Ej:se=\\Eq:so=\\Ep:ta=^I\
- :up=\\EA:ve=\\Ee:vi=\\Ef:km:bl=^G:cr=^M:ti=\\Ev\\Ee:sr=\\EI:sf=^J";
-
- /*
- * find_file find the termcap file and open it if possible
- *
- * Attempts to locate and open the termcap file. Also handles
- * using the environment TERMCAP string as the actual buffer
- * (that's why bp has to be an input parameter).
- *
- * If TERMCAP is defined an begins with a '/' character then
- * it is taken to be the pathname of the termcap file and
- * an attempt is made to open it. If this fails then
- * the default termcap file is used instead.
- *
- * If TERMCAP is defined but does not begin with a '/' then
- * it is assumed to be the actual buffer contents provided
- * that <name> matches the environment variable TERM.
- *
- * BUGS
- *
- * There is currently no way to be sure which termcap
- * file was opened since the default will always be
- * tried.
- *
- */
-
- static FILE *find_file(char *bp)
- {
- FILE *fp;
- char *cp;
- extern char *getenv (const char *);
-
- if ((cp = getenv("TERMCAP")) != NULL) {
- if (*cp != '\0') {
- if (*cp == '/' || *cp == '\\' || (cp[1] == ':')) {
- if ((fp = fopen(cp,"r")) != NULL) {
- return(fp);
- }
- } else {
- if (getenv("TERM") != NULL) {
- strcpy(bp,cp);
- return((FILE *)NULL);
- }
- }
- }
- }
- /* Try current directory, then /etc/termcap, then along the path
- */
- if ((fp = fopen(DEFAULT_ROOT, "r")) != NULL)
- return fp;
- else if ((fp = fopen(DEFAULT_FILE, "r")) != NULL)
- return fp;
- else if ((fp = nfopenp(DEFAULT_ROOT, "r", NULL)) != NULL)
- return fp;
- else {
- /*
- * if we do not have any better information, then
- */
- strcpy (bp, term_default);
- return (FILE *) NULL;
- }
- }
-
- /*
- *
- * tgetent load buffer with entry for specified terminal
- *
- * Extracts the entry for terminal <name> from the termcap file
- * and places it in the character buffer <bp>. It is currently
- * assumed that bp is at least 1024 characters. If the entry in
- * the termcap file is larger than 1023 characters the excess
- * characters will be discarded and appropriate status will
- * be returned.
- *
- * Also note that since bp is used by other termcap
- * routines, the storage associated with the termcap entry
- * cannot be freed until all termcap calls are completed.
- *
- * Tgetent can be directed to look in a file other than
- * the default (/etc/termcap) by defining an environment
- * variable called TERMCAP to be the pathname of the desired
- * termcap file. This is useful for debugging new entries.
- * NOTE: the pathname MUST begin with a '/' character.
- * (Atari ST specific change: the pathname may begin with '\',
- * or with a drive letter followed by ':').
- *
- * Also, if the string assigned to TERMCAP does not begin with
- * a '/' and if the environment variable TERM matches <name> then
- * the string assigned to TERMCAP is copied to buffer <bp>
- * instead of reading a termcap file.
- * (Atari ST specific change: TERM is no longer checked (the
- * check was buggy).
- *
- * Modification by ERS: if no termcap file can be found, then
- * a default termcap is used (this is for GEMDOS).
- *
- * Further mods by MJ: original routines fail to proces valid
- * termcap files - replaced with new versions.
- * Atari specific: default termcap used when nothing better is
- * around reads a number of rows and colums from Line-A variables.
- *
- * RETURNS
- *
- * -1 if the termcap file cannot be opened
- * 0 if no entry in termcap file matches <name>
- * 1 if extraction is successful with no errors
- * 2 if extraction is successful but entry truncated
- *
- * SEE ALSO
- *
- * tgetnum extract numeric type capability
- * tgetflag test boolean type capability
- * tgetstr get string value of capability
- *
- * AUTHOR
- *
- * Fred Fish
- *
- */
-
- int tgetent(bp,name)
- char *bp; /* Pointer to buffer (1024 char min) */
- char *name; /* Pointer to terminal entry to find */
- {
- FILE *fp;
-
- *bp = '\0';
- _tcpbuf = bp;
- if ((fp = find_file(bp)) == NULL) {
- if (*bp != '\0') {
- return(SUCCESS);
- } else {
- return(NO_FILE);
- }
- } else {
- *bp++ = ':';
- return (build_entry(bp, bp + BUFSIZE - 1, fp, name));
- }
- }
-
- /*
- *
- * tgetnum extract numeric option from termcap entry
- *
- * Returns numeric value of capability <id>, or -1 if <id>
- * is not found. Knows about octal numbers, which
- * begin with 0.
- *
- */
-
- extern char *_tcpbuf; /* Termcap entry buffer pointer */
-
- int tgetnum(id)
- char *id;
- {
- int value, base;
- char *bp;
-
- bp = _tcpbuf;
- while ((bp = strchr(bp,':')) != NULL) {
- bp++;
- if (*bp++ == id[0] && *bp != '\0' && *bp++ == id[1]) {
- if (*bp != '\0' && *bp++ != '#') {
- return(-1);
- } else {
- value = 0;
- if (*bp == '0') {
- base = 8;
- } else {
- base = 10;
- }
- while (isdigit(*bp)) {
- value *= base;
- value += (*bp++ - '0');
- }
- return(value);
- }
- }
- }
- return(-1);
- }
-
- /*
- *
- * tgoto expand cursor addressing string from cm capability
- *
- * Returns cursor addressing string, decoded from the cm
- * capability string, to move cursor to column destcol on
- * line destline.
- *
- * The following sequences uses one input argument, either
- * line or column, and place the appropriate substitution
- * in the output string:
- *
- * %d substitute decimal value (in ASCII)
- * %2 like %d but forces field width to 2
- * %3 like %d but forces field width to 3
- * %. like %c
- * %+x like %c but adds ASCII value of x
- *
- * The following sequences cause processing modifications
- * but do not "use up" one of the arguments. If they
- * act on an argument they act on the next one to
- * be converted.
- *
- * %>xy if next value to be converted is
- * greater than value of ASCII char x
- * then add value of ASCII char y.
- * %r reverse substitution of line
- * and column (line is substituted
- * first by default).
- * %i causes input values destcol and
- * destline to be incremented.
- * %% gives single % character in output.
- *
- * BUGS
- *
- * Does not implement some of the more arcane sequences for
- * radically weird terminals (specifically %n, %B, & %D).
- * If you have one of these you deserve whatever happens.
- *
- */
-
- #define MAXARGS 2
-
- static char *in; /* Internal copy of input string pointer */
- static char *out; /* Pointer to output array */
- static int args[MAXARGS]; /* Maximum number of args to convert */
- static int pcount; /* Count of args processed */
- static char output[64]; /* Converted string */
- static void process (void);
-
- char *tgoto(cm,destcol,destline)
- char *cm;
- int destcol;
- int destline;
- {
- if (cm == NULL) {
- return("");
- } else {
- in = cm;
- out = output;
- args[0] = destline;
- args[1] = destcol;
- pcount = 0;
- while (*in != '\0') {
- if (*in != '%') {
- *out++ = *in++;
- } else {
- process();
- }
- }
- *out = 0;
- return(output);
- }
- }
- /*
- * process process the conversion/command sequence
- *
- * Processes the sequence beginning with the % character.
- * Directly manipulates the input string pointer, the
- * output string pointer, and the arguments. Leaves
- * the input string pointer pointing to the next character
- * to be processed, and the output string pointer pointing
- * to the next output location. If conversion of
- * one of the numeric arguments occurs, then the pcount
- * is incremented.
- *
- */
-
- static void process(void)
- {
- int temp;
-
- in++;
- switch(*in++) {
- case 'd':
- sprintf(out,"%d",args[pcount++]);
- out = &output[(int)strlen(output)];
- break;
- case '2':
- sprintf(out,"%02d",args[pcount++]);
- out = &output[(int)strlen(output)];
- break;
- case '3':
- sprintf(out,"%03d",args[pcount++]);
- out = &output[(int)strlen(output)];
- break;
- case '.':
- *out++ = args[pcount++];
- break;
- case '+':
- *out++ = args[pcount++] + *in++;
- break;
- case '>':
- if (args[pcount] > *in++) {
- args[pcount] += *in++;
- } else {
- in++;
- }
- break;
- case 'r':
- temp = args[pcount];
- args[pcount] = args[pcount+1];
- args[pcount+1] = temp;
- break;
- case 'i':
- args[pcount]++;
- args[pcount+1]++;
- break;
- case '%':
- *out++ = '%';
- break;
- }
- }
-